#ifndef _INPUT_H_
#define _INPUT_H_

#ifdef _WIN32
#pragma once
#endif

/**
 * 01.03.12 - Steven Hartin - Copied over from a previous project, added
 *                            comments and slighlty modified code to work with
 *                            this project.
 */

#ifndef STRICT
#define STRICT
#endif

#ifndef DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION 0x0800
#endif

#include <Windows.h>
#include <map>
#include <string>
#include <vector>

#include <d3dx9.h>
#include <dinput.h>

using std::map;
using std::string;
using std::vector;

class CInputDevice;

enum INPUT_DEVICE {
    DEVICE_KEYBOARD,
    DEVICE_MOUSE
};

typedef struct {
    union {
        unsigned char charrKeyboardData[256];
        DIMOUSESTATE2 MouseState;
    };
    INPUT_DEVICE type;
    CInputDevice *pDevice;
} DEVICE_EVENT;

typedef void (*DEVICE_EVENT_CALLBACK)(const DEVICE_EVENT &);

class CInputDevice {
public:
    CInputDevice(const INPUT_DEVICE nDeviceType);
    ~CInputDevice();
    
    virtual void setUp(LPDIRECTINPUT8 pDirectInput, HWND hwndMain) = 0;
    virtual void processState() = 0;

    void registerEventListener(DEVICE_EVENT_CALLBACK);
    bool isActive() const;
    void setActive(bool bActive);
    LPDIRECTINPUTDEVICE8 *getDevice();
    void setDevice(LPDIRECTINPUTDEVICE8 pDevice);
    
    
    void cleanUp();
    INPUT_DEVICE getType() const;

protected:
    void processCallbacks(const DEVICE_EVENT &evt) const;

private:
    vector<DEVICE_EVENT_CALLBACK> m_arrCallbacks;
    bool m_bActive;
    const INPUT_DEVICE m_nDeviceType;

    LPDIRECTINPUTDEVICE8 m_pDevice;
    
};

class CInputDeviceManager {
public:
    static CInputDeviceManager *getInstance();

    CInputDevice *addDevice(string szIdentifier, CInputDevice *pInputDevice);
    CInputDevice* getDevice(string key) const;
    BOOL setUp(HINSTANCE hInst, HWND hwndMain);
    void processStates();
    
private:
    CInputDeviceManager();
    ~CInputDeviceManager();

    HINSTANCE m_hInst;
    HWND m_hwndMain;
    LPDIRECTINPUT8 m_pDirectInput;
    map<string, CInputDevice*> m_arrDevices;
};



#endif